<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECMAScript基础之继承(深入)</title>
</head>
<body>
    <script>
        // 插件化 独立作用域，避免全局污染
        ;(function(){
            // 原型链继承
            // 缺点：引用类型的值，可以被修改
            function Professor(){}
            Professor.prototype.tSkill = 'JAVA';
            var professor = new Professor();
            
            function Teacher(){
                this.mSkill = 'JS/JQ';
            }
            Teacher.prototype = professor;
            // Teacher.prototype.constructor = Teacher;
            var teacher = new Teacher();
            
            function Student(){
                this.pSkill = 'HTML/CSS';
            }
            // Student.prototype.constructor = Student;
            Student.prototype = teacher;

            var student = new Student();
            console.log(student);
        })()
        

        ;(function(){
            // 构造函数内部已有属性，则优先取内部属性
            function Car(){
                this.brand = 'Banz';
            }

            Car.prototype = {
                brand: 'Mazda',
                intro: function(){
                    console.log('我是' + this.brand + '车');
                }
            }

            var car = new Car();
            car.intro();
        })()

        ;(function(){
            function Person(){
                this.smoke = function(){
                    this.weight--;
                }
            }

            Person.prototype = {
                weight: 130
            }

            var person = new Person();
            person.smoke();
            
            console.log(person.weight); // 129
            console.log(Person.prototype.wieght); // 130
        })()

        ;(function(){
            var obj1 = {}
            console.log(obj1);

            var obj2 = new Object(); // 一般公司不用
            console.log(obj2);

            // __proto__ => Obj.prototype
            // 如果是自定义构造函数，那么__proto__指向自定义构造函数
            function Obj(){}
            var obj = new Obj();
            console.log(obj);
        })()

        ;(function(){
            // Object.create(对象（原型），null)，创建对象
            function Obj(){}
            Obj.prototype.num = 1;
            var obj1 = Object.create(Obj);
            var obj2 = new Object();

            console.log(obj1);
            console.log(obj2);
            // 两种是一样的
        })()

        ;(function(){
            // 重点：不是所有的对象都继承Object.prototype
            var obj = Object.create(null);
            obj.num = 1;
            // obj.toString(); // 报错，因为obj没有原型

            var obj1 = {
                count: 2
            }
            obj.__proto__ = obj1;
            console.log(obj.count); // __proto__是系统内置的，你可以更改，但不可以自造
            
            // undefined null   不能使用toString()方法
            // 为什么不能？原始值，没有原型，没有包装类，没有toString()
        })()

        ;(function(){
            var num = 1,
                obj = {},
                obj2 = Object.create(null);
            document.write(num);
            document.write(obj);
            // document.write(obj2); // 没有原型，继承不了Object.prototype
            // 自己加一个toString()，是可以的，但没有意义
            // obj2.toString = function(){
            //     return '你好'
            // }
            // document.write(obj2);

            // 原型方法的重写
            // Number.prototype.toString.call(1); // 1
            // Object.prototype.toString.call(1); // [object Number]
            
            
            // call/apply
            function test() {
                console.log('a');
            }
            test.call();

            function Car(brand, color){
                this.brand = brand;
                this.color = color;
            }
            var newCar = {};
            // Car.call(newCar, 'Banz', 'red');
            Car.apply(newCar, ['Banz', 'red']);
            console.log(newCar);
        })()

        ;(function(){
            //加减乘除
            function Compute(){
                this.plus = function(a, b){
                    console.log(a + b);
                };

                this.minus = function(a, b){
                    console.log(a - b);
                }
            }

            function FullCompute(){
                Compute.apply(this);
                this.mul = function(a, b){
                    console.log(a * b);
                }
                this.div = function(a, b){
                    console.log(a / b);
                }
            }

            var compute = new FullCompute();
            compute.plus(1, 2);
            compute.div(1, 2);
        })()
    </script>
</body>
</html>